<?php
/*
 +----------------------------------------------------------------------
 + Title        : GenModel 控制器
 + Author       : Randy_chen
 + Version      : V1.0.0.1
 + Initial-Time : 2021/2/28 8:13
 + Last-time    : 2021/2/28 8:13+ chen2
 + Desc         : GenModel
 +----------------------------------------------------------------------
*/

namespace app\command\gen;

use think\Config;
use think\console\Command;
use think\console\Input;
use think\console\input\Option;
use think\console\Output;
use think\Db;
use think\Exception;
use think\helper\Str;

class Validate extends Command {
	protected function configure()
	{
		$this->setName('gen:v')
			->addOption('table', 't', Option::VALUE_REQUIRED, 'table name without prefix', null)
		     ->setDescription(' 自动生成验证器 ');
	}

	protected function execute(Input $input, Output $output)
	{
		$table = $input->getOption('table') ?: '';
		$this->execute1($table);
		$output->writeln("gen model success");
	}

	protected $stubList = [];

	public function execute1($table) {

		$modelModuleName = 'common';
		$modelTableType = 'table';
		$prefix = Config::get('database.prefix');
		$model = Str::studly($table);

		$modelName = $table = stripos($table, $prefix) === 0 ? substr($table, strlen($prefix)) : $table;
		$modelTableTypeName = $modelTableName = $modelName;
		$table = $modelTableName;
		//从数据库中获取表字段信息
		$sql = "SELECT * FROM `information_schema`.`columns` "
			. "WHERE  table_name = ? "
			. "ORDER BY ORDINAL_POSITION";
		//加载主表的列
		$columnList = Db::query($sql, [$modelTableName]);
		$fieldArr = [];
		foreach ($columnList as $k => $v) {
			$fieldArr[] = $v['COLUMN_NAME'];
		}

		//模型
		[$modelNamespace, $modelName, $modelFile, $modelArr,
		 $notes] = $this->getModelData($modelModuleName, $model, $table, $columnList);


		$addList = [];
		$editList = [];
		$javascriptList = [];
		$langList = [];
		$field = 'id';
		$order = 'id';
		$priDefined = FALSE;
		$priKey = '';
		$relationPrimaryKey = '';
		foreach ($columnList as $k => $v) {
			if ($v['COLUMN_KEY'] == 'PRI') {
				$priKey = $v['COLUMN_NAME'];
				break;
			}
		}
		if (!$priKey) {
			throw new Exception('Primary key not found!');
		}
		$modelTableInfo = Db::query("SHOW TABLE STATUS LIKE '{$modelTableName}'", [], TRUE);
		$tableComment = $modelTableInfo[0]['Comment'];
		$tableComment = mb_substr($tableComment, -1) == '表' ? mb_substr($tableComment, 0, -1) . '管理' : $tableComment;

		$data = [
			'modelNamespace'          => $modelNamespace,
			'modelName'               => $modelName,
			'modelTableName'          => $modelTableName,
			'modelTableType'          => $modelTableType,
			'modelTableTypeName'      => $modelTableTypeName,
			'tableComment'            => $tableComment,
			'pk'                      => $priKey,
			'order'                   => $order,
			'table'                   => $table,
			'tableName'               => $modelTableName,
			'addList'                 => $addList,
			'editList'                => $editList,
			'javascriptList'          => $javascriptList,
			'langList'                => $langList,
			'modelAutoWriteTimestamp' => in_array('create_time', $fieldArr) || in_array('update_time', $fieldArr) ? "'int'" : 'false',
			'createTime'              => in_array('create_time', $fieldArr) ? "'create_time'" : 'false',
			'updateTime'              => in_array('update_time', $fieldArr) ? "'update_time'" : 'false',
			'notes'                   => $notes,
			'appendAttrList'          => '',//implode(",\n", $appendAttrList),
			'getEnumList'             => '',//implode("\n\n", $getEnumArr),
			'getAttrList'             => '',//implode("\n\n", $getAttrArr),
			'setAttrList'             => '',//implode("\n\n", $setAttrArr),
			'modelInit'               => '',//$modelInit,
		];

		$order = $priKey;
		$result = $this->writeToFile('validate', $data, $modelFile);
	}

	/**
	 * 写入到文件
	 *
	 * @param string $name
	 * @param array  $data
	 * @param string $pathname
	 *
	 * @return mixed
	 */
	protected function writeToFile($name, $data, $pathname) {
		foreach ($data as $index => &$datum) {
			$datum = is_array($datum) ? '' : $datum;
		}
		unset($datum);
		$content = $this->getReplacedStub($name, $data);

		if (!is_dir(dirname($pathname))) {
			mkdir(dirname($pathname), 0755, true);
		}
		return file_put_contents($pathname, $content);
	}

	/**
	 * 获取替换后的数据
	 *
	 * @param string $name
	 * @param array  $data
	 *
	 * @return string
	 */
	protected function getReplacedStub($name, $data) {
		foreach ($data as $index => &$datum) {
			$datum = is_array($datum) ? '' : $datum;
		}
		unset($datum);
		$search = $replace = [];
		foreach ($data as $k => $v) {
			$search[] = "{%{$k}%}";
			$replace[] = $v;
		}
		$stubname = $this->getStub($name);
		if (isset($this->stubList[$stubname])) {
			$stub = $this->stubList[$stubname];
		} else {
			$this->stubList[$stubname] = $stub = file_get_contents($stubname);
		}
		$content = str_replace($search, $replace, $stub);
		return $content;
	}

	/**
	 * 获取基础模板
	 *
	 * @param string $name
	 *
	 * @return string
	 */
	protected function getStub($name) {
		return __DIR__  . DS . 'stubs' . DS . $name . '.stub';
	}

	/**
	 * 获取模型相关信息
	 *
	 * @param $module
	 * @param $model
	 * @param $table
	 *
	 * @return array
	 */
	protected function getModelData($module, $model, $table, $columnList) {
		return $this->getParseNameData($module, $model, $table, 'validate', $columnList);
	}

	/**
	 * 获取已解析相关信息
	 *
	 * @param $module
	 * @param $name
	 * @param $table
	 * @param $type
	 *
	 * @return array
	 */
	protected function getParseNameData($module, $name, $table, $type, $columnList) {
		$arr = [];
		if (!$name) {
			$arr = explode('_', strtolower($table));
		} else {
			$name = str_replace(['.', '/', '\\'], '/', $name);
			$arr = explode('/', $name);
		}
		$parseName = ucfirst(array_pop($arr)).'Validate';
		$appNamespace = Config::get('app_namespace');
		$parseNamespace = "{$appNamespace}\\{$module}\\{$type}" . ($arr ? "\\" . implode("\\", $arr) : "");
		$moduleDir = APP_PATH . $module . DS;
		$parseFile = $moduleDir . $type . DS . ($arr ? implode(DS, $arr) . DS : '') . $parseName . '.php';
		$parseArr = $arr;
		$parseArr[] = $parseName;
		$notes = $this->getNotes($columnList);

		return [$parseNamespace, $parseName, $parseFile, $parseArr, $notes];
	}

	public function getNotes($columnList) {
		$str ='';
		foreach ($columnList as $v) {
			$str .= sprintf('\'%s\' => \'%s\' ,',  $v['COLUMN_NAME'], $v['COLUMN_COMMENT']) . PHP_EOL;
		}
		return $str;
	}
}
